package view.world;

import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.geom.Line2D;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import javax.imageio.ImageIO;
import javax.swing.ImageIcon;

import parameters.GUIParameters;
import view.BaseComponent;
import view.ImagePoint2D;
import controller.CompleteListener;


public class WorldPanel extends BaseComponent {

	private static final int PATH = 0;
	private static final int SELECTED_PATH = 1;
	private static final int GRENADE_EVENT = 2;
	private static final int ACTIVE_GRENADE_EVENT = 3;
	private static final int LOS_EVENT = 4;
	private static final int ACTIVE_LOS_EVENT = 5;
	
	private boolean playing;
	
	private Point selected;
	
	private List<Line2D> paths;
	private List<Line2D> selectedPaths;
	private List<Line2D> grenadeEvents;
	private List<Line2D> losEvents;
	private List<Line2D> activeGrenadeEvents;
	private List<Line2D> activeLOSEvents;
	private List<ImagePoint2D> players;
	private List<ImagePoint2D> grenades;
	
	private BufferedImage map;
	
	public WorldPanel(File mapFile) {
		// Loading the map :
		map = null;
		try {
			map = ImageIO.read(mapFile);
		} catch (IOException e) {
			return;
		}

		playing = false;
		
		selected = null;
		
		paths = new ArrayList<Line2D>();
		selectedPaths = new ArrayList<Line2D>();
		grenadeEvents = new ArrayList<Line2D>();
		losEvents = new ArrayList<Line2D>();
		players = new ArrayList<ImagePoint2D>();
		grenades = new ArrayList<ImagePoint2D>();
		
		this.setPreferredSize(new Dimension(map.getWidth(), map.getHeight()));
		this.setBackground(Color.lightGray);
	}
	
	public void updateSpecialLists(List<Line2D> selectedPaths_,
			List<Line2D> activeGrenadeEvents_,
			List<Line2D> activeLOSEvents_) {
		if (selectedPaths_ != null)
			selectedPaths = selectedPaths_;
		if (activeGrenadeEvents_ != null)
			activeGrenadeEvents = activeGrenadeEvents_;
		if (activeLOSEvents_ != null)
			activeLOSEvents = activeLOSEvents_;
		this.repaint();
	}
	
	public void updateStaticLists(List<Line2D> paths_,
			List<Line2D> grenadeEvents_,
			List<Line2D> losEvents_) {
		if (paths_!=null)
			paths = paths_;
		if (grenadeEvents_!=null)
			grenadeEvents = grenadeEvents_;
		if (losEvents_!=null)
			losEvents = losEvents_;
		this.repaint();
	}
	
	public void updateDynamicLists(List<ImagePoint2D> players_,
			List<ImagePoint2D> grenades_) {
		if (players_!=null)
			players = players_;
		if (grenades_!=null)
			grenades = grenades_;
		this.repaint();
	}
	
	@Override
	protected void paintComponent(Graphics tempg) {
		Graphics2D g = (Graphics2D) tempg;

		// Drawing the map :
		g.drawImage(map, 0, 0, null);
		
		// If in edit mode, drawing all the lines :
		if (!playing) {
			// Drawing the paths :
			drawLines(paths, PATH, g);
			// Drawing the paths of the selected player :
			drawLines(selectedPaths, SELECTED_PATH, g);
			// Drawing the grenadeEvents :
			drawLines(grenadeEvents, GRENADE_EVENT, g);
			// Drawing the active grenadeEvents :
			drawLines(activeGrenadeEvents, ACTIVE_GRENADE_EVENT, g);
			// Drawing losEvents :
			drawLines(losEvents, LOS_EVENT, g);
			// Drawing the active grenadeEvents :
			drawLines(activeLOSEvents, ACTIVE_LOS_EVENT, g);
		}
		// Drawing players and grenades :
		drawPoints(players, g);
		drawPoints(grenades, g);
		drawSelected(selected, g);
	}
	
	public void drawSelected(Point pt, Graphics2D g) {
		if (pt == null)
			return;
		g.setColor(Color.black);
		g.setStroke(new BasicStroke(4.0f));
		g.drawRect(pt.x-5, pt.y-5, 10, 10);
		g.setColor(Color.green);
		g.setStroke(new BasicStroke(2.0f));
		g.drawRect(pt.x-5, pt.y-5, 10, 10);
	}
	
	public void drawPoints(List<ImagePoint2D> list, Graphics2D g) {
		
		if (list == null)
			return;
		
		Iterator<ImagePoint2D> it = list.iterator();
		ImagePoint2D current;
		while (it.hasNext()) {
			current = it.next();
			ImageIcon icon = current.getIcon();
			g.drawImage(icon.getImage(),
					(int)current.getX()-icon.getIconWidth()/2,
					(int)current.getY()-icon.getIconHeight()/2,
					null);
		}
		it = list.iterator();
		while (it.hasNext()) {
			current = it.next();
			if (current.hasName()) {
				g.setColor(GUIParameters.STRING_COLOR);
				g.drawString(current.getName(),
						(int)current.getX()-current.getName().length()*3, (int)current.getY()+20);
			}
		}
	}
	
	public void drawLines(List<Line2D> list, int style, Graphics2D g) {
		
		if (list == null)
			return;
		
		float[] dash = {2,4};
		
		// Setting style :
		switch (style) {
		case PATH :
			g.setColor(GUIParameters.PATH_COLOR);
			g.setStroke(new BasicStroke(1.0f));
			break;
		case SELECTED_PATH :
			g.setColor(GUIParameters.PATH_COLOR);
			g.setStroke(new BasicStroke(2.0f));
			break;
		case GRENADE_EVENT :
			g.setColor(GUIParameters.GRENADE_COLOR);
			g.setStroke(new BasicStroke(1.0f,
					BasicStroke.CAP_SQUARE,BasicStroke.JOIN_BEVEL,0f,
					dash,0f));
			break;
		case ACTIVE_GRENADE_EVENT :
			g.setColor(GUIParameters.GRENADE_COLOR);
			g.setStroke(new BasicStroke(2.0f,
					BasicStroke.CAP_SQUARE,BasicStroke.JOIN_BEVEL,0f,
					dash,0f));
			break;
		case LOS_EVENT :
			g.setColor(GUIParameters.LOS_COLOR);
			g.setStroke(new BasicStroke(1.0f,
					BasicStroke.CAP_SQUARE,BasicStroke.JOIN_BEVEL,0f,
					dash,0f));
			break;
		case ACTIVE_LOS_EVENT :
			g.setColor(GUIParameters.LOS_COLOR);
			g.setStroke(new BasicStroke(2.0f,
					BasicStroke.CAP_SQUARE,BasicStroke.JOIN_BEVEL,0f,
					dash,0f));
			break;
		default:
			g.setColor(Color.black);
			break;
		}
		
		Iterator<Line2D> it = list.iterator();
		Line2D current;
		while (it.hasNext()) {
			current = it.next();
			g.drawLine((int)current.getX1(), (int)current.getY1(),
					(int)current.getX2(), (int)current.getY2());
		}
	}
	
	@Override
	public void attachListener(CompleteListener l) {
		this.addMouseListener(l);
		this.addMouseMotionListener(l);
	}

	@Override
	public void setEnabled(boolean enable) {}

	public List<Line2D> getGrenadeEvents() {
		return grenadeEvents;
	}

	public List<Line2D> getLosEvents() {
		return losEvents;
	}

	public List<Line2D> getPaths() {
		return paths;
	}

	public List<Line2D> getSelectedPaths() {
		return selectedPaths;
	}

	public Point getSelected() {
		return selected;
	}
	
	public void setSelected(Point selected) {
		this.selected = selected;
		this.repaint();
	}

}
